package scalaLearning.scoptCommandParse

import com.typesafe.config.ConfigFactory
import org.apache.spark.sql.SparkSession
import scopt.OptionParser
import java.io.File


object SparkFilesArgs extends App  {
  case class Config(foo: Int = -1,
                    out: File = new File("."),
                    xyz: Boolean = false,
                    libName: String = "",
                    maxCount: Int = -1,
                    verbose: Boolean = false,
                    debug: Boolean = false,
                    mode: String = "",
                    files: Seq[File] = Seq(),
                    keepalive: Boolean = false,
                    jars: Seq[File] = Seq(),
                    kwargs: Map[String,String] = Map())
//  val parser = new OptionParser[Config]("SparkFilesArgs") {
//
//    opt[String]('c', "conf")
//        .text("config.resource for telematics")
//        .action((x, c) => c.copy(mode = x))
//
//    help("help").text("prints this usage text")
//  }

  val parser = new scopt.OptionParser[Config]("scopt") {
    head("scopt", "3.x")

    opt[Int]('f', "foo").
        action( (x, c) => c.copy(foo = x) ).
        text("foo is an integer property")

    opt[File]('o', "out").required().valueName("<file>").
        action( (x, c) => c.copy(out = x) ).
        text("out is a required file property")

    opt[(String, Int)]("max").action({
      case ((k, v), c) => c.copy(libName = k, maxCount = v) }).
        validate( x =>
          if (x._2 > 0) success
          else failure("Value <max> must be >0") ).
        keyValueName("<libname>", "<max>").
        text("maximum count for <libname>")

    opt[Seq[File]]('j', "jars").valueName("<jar1>,<jar2>...").action( (x,c) =>
      c.copy(jars = x) ).text("jars to include")

    opt[Map[String,String]]("kwargs").valueName("k1=v1,k2=v2...").action( (x, c) =>
      c.copy(kwargs = x) ).text("other arguments")

    opt[Unit]("verbose").action( (_, c) =>
      c.copy(verbose = true) ).text("verbose is a flag")

    opt[Unit]("debug").hidden().action( (_, c) =>
      c.copy(debug = true) ).text("this option is hidden in the usage text")

    help("help").text("prints this usage text")

    arg[File]("<file>...").unbounded().optional().action( (x, c) =>
      c.copy(files = c.files :+ x) ).text("optional unbounded args")

    note("some notes.".toString)

    cmd("update").action( (_, c) => c.copy(mode = "update") ).
        text("update is a command.").
        children(
          opt[Unit]("not-keepalive").abbr("nk").action( (_, c) =>
            c.copy(keepalive = false) ).text("disable keepalive"),
          opt[Boolean]("xyz").action( (x, c) =>
            c.copy(xyz = x) ).text("xyz is a boolean property"),
          opt[Unit]("debug-update").hidden().action( (_, c) =>
            c.copy(debug = true) ).text("this option is hidden in the usage text"),
          checkConfig( c =>
            if (c.keepalive && c.xyz) failure("xyz cannot keep alive")
            else success )
        )
  }

  /**
    * 以上生成以下用法文本：
    * scopt 3.x
    * Usage: scopt [update] [options] [<file>...]
    *
    * -f, --foo <value>        foo is an integer property
    * -o, --out <file>         out is a required file property
    * --max:<libname>=<max>    maximum count for <libname>
    * -j, --jars <jar1>,<jar2>...    jars to include
    * --kwargs k1=v1,k2=v2...  other arguments
    * --verbose                verbose is a flag
    * --help                   prints this usage text
    * <file>...                optional unbounded args
    * some notes.
    *
    * Command: update [options]
    * update is a command.
    * -nk, --not-keepalive     disable keepalive
    * --xyz <value>            xyz is a boolean property
    */

  // parser.parse returns Option[C]
  parser.parse(args, Config()) match {
    case Some(config) =>
    // do stuff

    case None =>
    // arguments are bad, error message will have been displayed
  }


  // 解析命令行参数
//  parser.parse(args, Config()) match {
//    case Some(params) => println(params)
//    case _ => sys.exit(1)
//  }

  // 本地模式运行,便于测试
  val spark = SparkSession.builder()
      .appName(this.getClass.getName)
      .master("local[3]")
      .getOrCreate()

  spark.sparkContext.setLogLevel("WARN")

  val df  = spark.read.csv("data/csv.txt")
  df.show()

  ConfigFactory.invalidateCaches() // 清理配置缓存
  lazy val config = ConfigFactory.load()
  println(config.origin())
  lazy val sparkConf = config.getConfig("spark")
  lazy val sparkMaster = sparkConf.getString("master")
  lazy val checkPath = sparkConf.getString("checkpoint.path")
  println(sparkMaster, checkPath)
  spark.stop()
}
